import { FileInfo, FileUploadConfig, FileUploadListener } from "../FileServerClient";
import UUID from "../../../common/UUID";
import Beans from "../../../common/utils";
import Logger from "../../../log/Logger";
import Fetch from "./Fetch";
import AbstractClient from "./AbstractClient";


class FetchResponse {
    type: string = '';
    status: number = 0;
    ok: boolean = false;
}

/**
 *  Note: 不建议使用(1. 没有文件上传进度显示; 2. 无法获取上传文件的大小)
 *  fetch 文件上传客户端.
 *  适用SDK 平台: ReactNative(Android, ios)
 *  配置方式
 sdkConfig.fileServerConfig = {
        use: 'aliyun',
        // use: 'local',
        client: 'rn-fetch',
        baseUrl: 'http://192.168.0.100:8082',
        version: 'v1',
    };
 *
 * */

// 文件服务器Fetch客户端
export default class ReactNativeFetchClient extends AbstractClient{
    init(uploadConfig: FileUploadConfig, listeners: FileUploadListener | undefined): void {
        const self = this;
        self.uploadConfig = uploadConfig;
        if(listeners !== undefined){
            this.beforeUploadCallback = listeners.beforeUploadCallback;
            this.progressCallback = listeners.progressCallback;
            this.uploadedCallback = listeners.uploadedCallback;
            this.errorCallback = listeners.errorCallback;
        }
    }

    public upload(path:string):string{
        const self = this;
        // 触发用户额外自定义的 beforeUploadCallback 事件
        let fileInfo = new FileInfo();
        if(!path){
            this.setErrorCallback(603, '文件路径为空');
            return "";
        }
        const filename = path.substring(path.lastIndexOf("/")+1);
        if(!filename){
            this.setErrorCallback(604, '无法获取文件名:' + filename);
            return "";
        }
        fileInfo.id = UUID.gen();
        fileInfo.name = filename;
        fileInfo.originFileName = filename;
        fileInfo.size = 0; // 服务器计算?
        fileInfo.type = self.getFileType(filename); // 若为空, 通过后缀名确认文件类型
        if(typeof self.beforeUploadCallback === 'function'){
            const info = self.beforeUploadCallback(fileInfo);
            if(info){
                self.fileInfo = info;
            }
            else {
                self.fileInfo = fileInfo;
            }
        }
        else {
            self.fileInfo = fileInfo;
        }

        self.buildFormParams(fileInfo, function (host, formData) {
            self.applyLocalServerUploadDo(path, host, formData)
            // self.applyReactNativeXMLHttpUploadDo(path, host, formData)
        });


        return fileInfo.id;
    }


    // 本地上传的细节处理 self: fileclient 实例
    private applyLocalServerUploadDo(filePath, host, formParams:any):void {
        const fetch = Fetch.getFetchToolkit();
        const self = this;
        if(!self.signInfo || !self.fileInfo){
            return;
        }
        let uploadUrl = '';
        if(this.serverConfig.use === 'local'){
            uploadUrl = (self.serverConfig.baseUrl + '/' + self.serverConfig.version + '/' + 'common/file/upload');
        }
        else if(this.serverConfig.use === 'aliyun'){
            uploadUrl = host;
        }
        let formData = new FormData();
        for(const v in formParams){
            formData.append(v, formParams[v]);
        }
        // use FILE PROTOCOL access the file
        let file = {
            uri: 'file://' + filePath,
            type: self.getMimeType(self.fileInfo.originFileName),
            name: self.fileInfo.originFileName
        };
        formData.append("file", file as any);
        let options:any = {};
        options.body = formData;
        options.method = 'POST';
        options.headers = {
            'Content-Type': 'multipart/form-data',
        };
        console.log(`ready fetch upload:${uploadUrl}  with options:${Beans.json(options)}  fileInfo:${Beans.json(self.fileInfo)}`);

        if(self.serverConfig.use === 'aliyun'){
            fetch(uploadUrl, options)
                .then((res)=> {
                    self.handleAliyunServerResponse(res as FetchResponse);
                }).catch((e)=>{
                Logger.trace(e);
                self.setErrorCallback(803, "上传文件失败,原因:"+e);
            });
        }
        else if(self.serverConfig.use === 'local'){
            fetch(uploadUrl, options)
                .then((res)=>res.json())
                .then((res)=> {
                    self.handleLocalServerResponse(res as any);
                }).catch((e)=>{
                Logger.trace(e);
                self.setErrorCallback(803, "上传文件失败,原因:"+e);
            });
        }
    };

    private handleLocalServerResponse(res:any){
        const self = this;
        if(!res.data || !res.data.url){
            self.setErrorCallback(801, "上传文件失败, 服务器返回:" + res.msg);
            return;
        }
        if(!self.fileInfo){
            return;
        }
        self.fileInfo.url = res.data.url;
        // 上传完成
        if(typeof self.uploadedCallback === 'function'){
            self.fileInfo.uploadPercent = 100;
            self.uploadedCallback(self.fileInfo);
        }
    }

    private handleAliyunServerResponse(response:FetchResponse){
        const self = this;

        function aliyunResponseDetailLog(response:FetchResponse) {
            // @ts-ignore
            return `response: ${Beans.json(response)}`
        }
        if (response.status === 200) {
            // 阿里云上传成功返回值放在头部内, body没有返回值
            console.debug(`上传文件成功, 服务器返回:${aliyunResponseDetailLog(response)}`);
            if(!self.fileInfo){
                return;
            }
            self.sendSyncUploadCallback({
                filename: self.signInfo.dir,
                originFileName: self.fileInfo.originFileName,
                fileType: self.fileInfo.type
            }).then((resp=>{
                // 同步回调发送完成
                if(typeof self.uploadedCallback === 'function' && self.fileInfo !== undefined && self.signInfo !== undefined){
                    self.fileInfo.uploadPercent = 100;
                    self.fileInfo.url = self.signInfo.host + '/' + self.signInfo.dir;
                    self.uploadedCallback(self.fileInfo);
                }
            })).catch(e =>{
                Logger.trace(e)
                self.setErrorCallback(701, e+"");
            });
        }
        else {
            self.setErrorCallback(801,
                // @ts-ignore
                `上传文件失败, 服务器返回:${aliyunResponseDetailLog(response)}`);
        }
    }


}
